using SharpDX.DirectInput;
using System;

namespace Engine.Input
{
    /// <summary>
    /// Creates a new Mouse-Device.
    /// </summary>
    public class MouseInput
    {
        #region Private Fields

        private int axisX, axisY, axisZ;
        private bool buttonL, buttonR, buttonM, buttonLreleased, buttonRreleased, buttonMreleased, mouseButtonLeft, mouseButtonRight, mouseLeftPressingStarted, mouseRightPressingStarted;
        private bool hasMovedWhilePressingL, hasMovedWhilePressingR, hasMovedWhilePressingM;
        private Mouse mouse = null;
        private MouseState state;

        #endregion Private Fields

        #region Public Constructors

        /// <summary>
        /// Creates a new Mouse-Device and assign it to the given Form
        /// </summary>
        /// <param name="form">the form where the mouse interacting with</param>
        public MouseInput(IntPtr form)
        {
            try
            {
                Helpers.LogWriter.Write(0, "Create DirectInput");
                DirectInput di = new DirectInput();
                //var devices =  di.GetDevices();
                //  foreach (var item in devices)
                //  {
                //      if (item.Type == DeviceType.Mouse)
                //      {
                //          //this.mouse = new Mouse(di);
                //      }
                //  }

                Helpers.LogWriter.Write(0, "Create MouseDevice");
                this.mouse = new Mouse(di);
                Helpers.LogWriter.Write(0, "Create CooperateLevelForMouse");
                this.mouse.SetCooperativeLevel(form, CooperativeLevel.Background | CooperativeLevel.NonExclusive);
                //mouse.SetDataFormat(DeviceDataFormat.Mouse);
                Helpers.LogWriter.Write(0, "Acquire MouseDevice");
                this.mouse.Acquire();
                this.state = new MouseState();
                Helpers.LogWriter.Write(0, "Update MouseState");
                Update();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        #endregion Public Constructors

        #region Public Properties

        /// <summary>
        /// returns the Speed from the X-Axis
        /// </summary>
        public int AxisX
        {
            get
            {
                return this.axisX;
            }
        }

        /// <summary>
        /// returns the Speed from the Y-Axis
        /// </summary>
        public int AxisY
        {
            get
            {
                return this.axisY;
            }
        }

        /// <summary>
        /// returns the Speed from the Z-Axis
        /// </summary>
        public int AxisZ
        {
            get
            {
                return this.axisZ;
            }
        }

        /// <summary>
        /// Checks if the left mouse-button is pressed
        /// </summary>
        public bool ButtonL
        {
            get
            {
                return this.buttonL;
            }
        }

        /// <summary>
        /// Checks if the left mouse-button is pressed since the last Update
        /// </summary>
        public bool ButtonLeftPressingStarted
        {
            get
            {
                return this.mouseLeftPressingStarted;
            }
        }

        /// <summary>
        /// Checks if the left mouse-button is released since the last Update
        /// </summary>
        public bool ButtonLreleased
        {
            get
            {
                return this.buttonLreleased;
            }
        }

        /// <summary>
        /// Checks if the middle mouse-button is pressed
        /// </summary>
        public bool ButtonM
        {
            get
            {
                return this.buttonM;
            }
        }

        public bool ButtonMreleased
        {
            get { return this.buttonMreleased; }
            set { this.buttonMreleased = value; }
        }

        /// <summary>
        /// Checks if the right mouse-button is pressed
        /// </summary>
        public bool ButtonR
        {
            get
            {
                return this.buttonR;
            }
        }

        /// <summary>
        /// Checks if the right mouse-button is pressed since the last Update
        /// </summary>
        public bool ButtonRightPressingStarted
        {
            get
            {
                return this.mouseRightPressingStarted;
            }
        }

        /// <summary>
        /// Checks if the right mouse-button is released since the last Update
        /// </summary>
        public bool ButtonRreleased
        {
            get
            {
                return this.buttonRreleased;
            }
        }

        /// <summary>
        /// Checks if the Mouse has moved while pressing the Left Mousebutton.
        /// </summary>
        public bool HasMovedWhilePressingL
        {
            get
            {
                return this.hasMovedWhilePressingL;
            }
            set
            {
                this.hasMovedWhilePressingL = value;
            }
        }

        /// <summary>
        /// Checks if the Mouse has moved while pressing the Middle Mousebutton.
        /// </summary>
        public bool HasMovedWhilePressingM
        {
            get
            {
                return this.hasMovedWhilePressingM;
            }
            set
            {
                this.hasMovedWhilePressingM = value;
            }
        }

        /// <summary>
        /// Checks if the Mouse has moved while pressing the right Mousebutton.
        /// </summary>
        public bool HasMovedWhilePressingR
        {
            get
            {
                return this.hasMovedWhilePressingR;
            }
            set
            {
                this.hasMovedWhilePressingR = value;
            }
        }

        #endregion Public Properties

        #region Public Methods

        /// <summary>
        /// Read the new Mousestate and Updates the properties
        /// </summary>
        public void Update()
        {
            if (this.mouse == null || this.mouse.IsDisposed)
                return;

            this.state = this.mouse.GetCurrentState();
            this.axisX = this.state.X;
            this.axisY = this.state.Y;
            this.axisZ = this.state.Z;
            bool[] buttons = this.state.Buttons;

            this.buttonL = buttons.Length > 0 && buttons[0] != false; //state[Mouse.Button0];
            this.buttonR = buttons.Length > 0 && buttons[1] != false; //state[Mouse.Button1];
            this.buttonM = buttons.Length > 0 && buttons[2] != false; //state[Mouse.Button2];

            this.mouseLeftPressingStarted = false;
            this.mouseRightPressingStarted = false;

            if (this.buttonL)
            {
                if (this.buttonL == this.mouseButtonLeft)
                {
                    this.mouseLeftPressingStarted = false;
                }
                else
                {
                    this.mouseLeftPressingStarted = true;
                }
            }
            if (this.buttonR)
            {
                if (this.buttonR == this.mouseButtonRight)
                {
                    this.mouseRightPressingStarted = false;
                }
                else
                {
                    this.mouseRightPressingStarted = true;
                }
            }

            if (this.mouseButtonLeft != this.buttonL && !this.buttonL)
            {
                this.buttonLreleased = true;
            }
            else
            {
                this.buttonLreleased = false;
            }

            if (this.mouseButtonRight != this.buttonR && !this.buttonR)
            {
                this.buttonRreleased = true;
            }
            else
            {
                this.buttonRreleased = false;
            }

            if (!this.buttonL)
            {
                if (!this.buttonLreleased)
                {
                    this.hasMovedWhilePressingL = false;
                }
            }
            if (!this.buttonR)
            {
                if (!this.buttonRreleased)
                {
                    this.hasMovedWhilePressingR = false;
                }
            }
            if (!this.buttonM)
            {
                this.hasMovedWhilePressingM = false;
            }

            if (!this.hasMovedWhilePressingL)
            {
                if (this.buttonL)
                {
                    if (this.axisX != 0 || this.axisY != 0)
                    {
                        this.hasMovedWhilePressingL = true;
                    }
                }
            }

            if (!this.hasMovedWhilePressingR)
            {
                if (this.buttonR)
                {
                    if (this.axisX != 0 || this.axisY != 0)
                    {
                        this.hasMovedWhilePressingR = true;
                    }
                }
            }
            if (!this.hasMovedWhilePressingM)
            {
                if (this.buttonM)
                {
                    if (this.axisX != 0 || this.axisY != 0)
                    {
                        this.hasMovedWhilePressingM = true;
                    }
                }
            }

            this.mouseButtonLeft = this.buttonL;
            this.mouseButtonRight = this.buttonR;
        }

        #endregion Public Methods

        #region Internal Methods

        internal void Dispose()
        {
            if (this.mouse != null)
                this.mouse.Dispose();
        }

        #endregion Internal Methods
    }
}